//
//  main.swift
//  Preprocessor
//
//  Created by Krunoslav Zaher on 4/22/15.
//  Copyright (c) 2015 Krunoslav Zaher. All rights reserved.
//

import Foundation

if Process.argc != 3 {
    print("./Preprocessor <source-files-root> <derived-data> ")
    exit(-1)
}

let sourceFilesRoot = Process.arguments[1]
let derivedData = Process.arguments[2]

let fileManager = NSFileManager()

func escape(value: String) -> String {
    let escapedString = value.stringByReplacingOccurrencesOfString("\n", withString: "\\n")
    let escapedString1 = escapedString.stringByReplacingOccurrencesOfString("\r", withString: "\\r")
    let escapedString2 = escapedString1.stringByReplacingOccurrencesOfString("\"", withString: "\\\"")
    
    return "\"\(escapedString2)\""
}

func processFile(path: String, outputPath: String) -> String {
    let rawContent = NSData(contentsOfFile: path)!
    let content = NSString(data: rawContent, encoding: NSUTF8StringEncoding)! as String
    
    let components = content.componentsSeparatedByString("<%")
    
    var functionContentComponents: [String] = []
    functionContentComponents.append("var components: [String] = [\"// This file is autogenerated.\\n// Take a look at `Preprocessor` target in RxSwift project \\n\"]\n")
    functionContentComponents.append("components.append(\(escape(components[0])))\n")
    
    for codePlusSuffix in (components[1 ..< components.count]) {
        let codePlusSuffixSeparated = codePlusSuffix.componentsSeparatedByString("%>")
        if codePlusSuffixSeparated.count != 2 {
            fatalError("Error in \(path) near \(codePlusSuffix)")
        }
        
        let code = codePlusSuffixSeparated[0]
        let suffix = codePlusSuffixSeparated[1]
        
        if code.hasPrefix("=") {
            functionContentComponents.append("components.append(String(\(code.substringFromIndex(code.startIndex.successor()))))\n")
        }
        else {
            functionContentComponents.append("\(code)\n")
        }
        
        functionContentComponents.append("components.append(\(escape(suffix)));\n")
    }
    
    functionContentComponents.append("try! components.joinWithSeparator(\"\").writeToFile(\"\(outputPath)\", atomically: false, encoding: NSUTF8StringEncoding)")
    
    return functionContentComponents.joinWithSeparator("")
}

func runCommand(path: String) {
    _ = NSProcessInfo().processIdentifier
    
    let task = NSTask()
    task.launchPath = "/bin/bash"
    task.arguments = ["-c", "xcrun swift \"\(path)\""]
    
    task.launch()
    
    task.waitUntilExit()
    
    if task.terminationReason != NSTaskTerminationReason.Exit {
        exit(-1)
    }
}

let files = fileManager.subpathsAtPath(sourceFilesRoot)

var generateAllFiles = ["// Generated code\n", "import Foundation\n"]

for file in files! {
    if ((file as NSString).pathExtension ?? "") != "tt" {
        continue
    }
    
    print(file)
    
    let path = (sourceFilesRoot as NSString).stringByAppendingPathComponent(file as String)
    
    let outputPath = path.substringToIndex(path.endIndex.predecessor().predecessor().predecessor()) + ".swift"
    
    generateAllFiles.append("_ = { () -> Void in\n\(processFile(path, outputPath: outputPath))\n}()\n")
}

let script = generateAllFiles.joinWithSeparator("")
let scriptPath = (derivedData as NSString).stringByAppendingPathComponent("_preprocessor.sh")

do {
    try script.writeToFile(scriptPath, atomically: true, encoding: NSUTF8StringEncoding)
} catch _ {
}
runCommand(scriptPath)